Skip to content

feat(shared): MethodDispatchIndex materialized view over HeritageMap (#914, RFC #909 Ring 2 SHARED)#960

Merged
magyargergo merged 1 commit into
mainfrom
rfc/scope-resolution/914-method-dispatch-index
Apr 18, 2026
Merged

feat(shared): MethodDispatchIndex materialized view over HeritageMap (#914, RFC #909 Ring 2 SHARED)#960
magyargergo merged 1 commit into
mainfrom
rfc/scope-resolution/914-method-dispatch-index

Conversation

@magyargergo

Copy link
Copy Markdown
Collaborator

Closes #914.

Scope

Implements RFC §3.1 MethodDispatchIndex: a two-way, DefId-keyed materialized view for O(1) method dispatch.

  • gitnexus-shared/src/scope-resolution/method-dispatch-index.ts
  • gitnexus/test/unit/scope-resolution/method-dispatch-index.test.ts (19 tests)

What it provides

interface MethodDispatchIndex {
  readonly mroByOwnerDefId:       ReadonlyMap<DefId, readonly DefId[]>;
  readonly implsByInterfaceDefId: ReadonlyMap<DefId, readonly DefId[]>;

  mroFor(ownerDefId: DefId):          readonly DefId[];
  implementorsOf(interfaceDefId: DefId): readonly DefId[];
}
  • mroByOwnerDefId — owner class → full MRO ancestor chain (excludes self, in per-language strategy order).
  • implsByInterfaceDefId — interface/trait → classes that implement it.

Why callbacks, not a shared strategy registry

The five existing MRO strategies (Python C3, Ruby kind-aware, Java/Kotlin linear, Rust qualified-syntax, COBOL none) live in the CLI package and depend on CLI-local `HeritageMap` + `SemanticModel`. Migrating them to `gitnexus-shared` would require pulling both — out of scope for #914.

`buildMethodDispatchIndex` instead takes `computeMro` / `implementsOf` callbacks and inverts + materializes. No MRO logic reimplemented.

interface MethodDispatchInput {
  readonly owners: readonly DefId[];
  readonly computeMro:    (ownerDefId: DefId) => readonly DefId[];
  readonly implementsOf:  (ownerDefId: DefId) => readonly DefId[];
}

Safety surface (matches sibling indexes)

  • First-write-wins on duplicate owners (parity with RING2-SHARED-2: DefIndex / ModuleScopeIndex / QualifiedNameIndex build functions #913 DefIndex / ModuleScopeIndex).
  • Dedup within callback output — repeated `(interface, owner)` pairs collapse to one.
  • Frozen stored arrays — `Object.freeze` on every bucket; shared frozen empty-array on miss so callers can iterate without null checks.
  • Callback-array isolation — we `.slice()` returns, so later mutation of the callback's source array doesn't leak in.

Tests (19, all passing)

  • Empty / degenerate: no owners · owner with no parents or interfaces
  • MRO materialization: single-inheritance chain · C3 diamond (Python) · BFS diamond (Java) · Ruby kind-aware mixin order · Rust qualified-syntax empty
  • Implements inversion: single mapping · multiple implementors per interface · iteration order preserved · dedup within a callback call · dedup across duplicate owners (+ first-write-wins verified via call counter)
  • Safety surface: frozen miss (MRO + implementors) · frozen bucket arrays · callback-array isolation
  • Readonly surface: iterable `mroByOwnerDefId` / `implsByInterfaceDefId` Maps

Verification

  • `tsc --noEmit` clean (both `gitnexus-shared` and `gitnexus`)
  • `gitnexus-shared` build clean
  • 19/19 new tests pass
  • Combined scope-resolution / model / shadow suite: 170/170 pass

Module placement

`gitnexus-shared/src/scope-resolution/method-dispatch-index.ts` — keeps all RFC §3.1 indexes under one folder alongside `def-index`, `module-scope-index`, `qualified-name-index`, and `resolve-type-ref`. Minor deviation from the issue's suggested `gitnexus-shared/src/method-dispatch-index.ts` for consistency.

Part of

…914, RFC #909 Ring 2 SHARED)

Implements RFC §3.1 `MethodDispatchIndex`: a two-way materialized view
keyed by `DefId` for O(1) method-dispatch resolution:

  - `mroByOwnerDefId`       — owner class → full MRO ancestor chain
                              (excludes self, per-language strategy order)
  - `implsByInterfaceDefId` — interface/trait → classes that implement it

**Not an MRO implementation.** `buildMethodDispatchIndex` is a pure
aggregator that calls back into caller-provided `computeMro` and
`implementsOf` functions. The five existing strategies (Python C3, Ruby
kind-aware, Java/Kotlin linear, Rust qualified-syntax, COBOL none) stay
where they are today (`model/resolve.ts`, `languages/ruby.ts`); this index
does not reimplement them.

Why callbacks rather than a shared registry: the strategies depend on the
CLI's `HeritageMap` + `SemanticModel`. Migrating both to `gitnexus-shared`
is out of scope for #914; callbacks let the shared build stay pure.

Module placement: `gitnexus-shared/src/scope-resolution/method-dispatch-index.ts`
for consistency with the other RFC §3.1 indexes (#913 DefIndex /
ModuleScopeIndex / QualifiedNameIndex; #916 resolveTypeRef).

Safety surface mirrors sibling indexes:
  - First-write-wins on duplicate owners.
  - Repeated (interface, owner) pairs deduplicated.
  - Stored arrays are `Object.freeze`d; caller mutation of the source
    array does not leak into the index.
  - Miss returns a shared frozen empty array.

Tests (19, all passing): empty input, single-inheritance chain, Python
C3 diamond, Java BFS, Ruby kind-aware mixin, Rust qualified-syntax empty,
interface inversion (single, multiple, ordered), dedup within and across
callback calls, frozen miss + bucket arrays, callback-array isolation,
readonly Map iteration.

Closes part of #909.
@vercel

vercel Bot commented Apr 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gitnexus Ready Ready Preview, Comment Apr 18, 2026 3:15pm

Request Review

@magyargergo

Copy link
Copy Markdown
Collaborator Author

@claude Act as a senior reviewer for GitNexus. Your job is to determine whether this PR is production-ready for this repo, not to give a generic code review.

You are reviewing a PR in the GitNexus monorepo:

  • gitnexus/ → CLI + MCP
  • gitnexus-web/
  • gitnexus-shared/

Your task has 2 phases, in this exact order:

PHASE 1 — DEFINE THE BAR
Before reviewing the diff, establish a concise repo-specific definition of “production-ready” for GitNexus, based only on the repo docs and the affected area.
Keep this definition practical and reviewable. Do not invent standards that are not grounded in the repo.

PHASE 2 — REVIEW THE PR AGAINST THAT BAR
Review the actual diff only after defining the bar.
Stay tightly scoped to the changed code and its direct consequences.


CONTEXT TO LOAD FIRST
Read these before reviewing:

  • AGENTS.md
  • GUARDRAILS.md
  • CONTRIBUTING.md
  • TESTING.md
  • ARCHITECTURE.md

Additional context:


PRIMARY OBJECTIVE
Decide whether this PR is safe, correct, maintainable, and operationally acceptable to merge into production for GitNexus.

Do not optimize for completeness at the expense of signal.
Do not pad the review.
Do not propose unrelated refactors.
Do not restate the PR description unless needed for verification.


REVIEW RULES

  • Every finding must be grounded in specific evidence from the diff or directly relevant surrounding code.
  • Every finding must include path:line.
  • If you make a behavioral claim, cite the code that proves it.
  • If you make a performance claim, explain the mechanism.
  • If something cannot be verified from the diff alone, explicitly say so.
  • Distinguish clearly between:
    • verified issue
    • plausible risk
    • unverified concern
  • Avoid vague wording like “might be better” or “could be improved” unless you explain exactly why.
  • Keep the review focused on this PR’s scope only.

For each finding, assign one severity:

  • BLOCKING → must be fixed before merge
  • NON-BLOCKING → valid issue, but merge may still be acceptable
  • NIT → stylistic/minor, not merge-relevant

REPO-SPECIFIC REVIEW CHECKLIST
Use these exact headings.

1. Correctness & functional completeness

Check:

  • Does the implementation actually satisfy the PR claim?
    • ManifestExtractor is truly invoked
    • config.links produces non-zero cross-links where expected
  • Resolver contracts are preserved:
    • resolveSymbol remains exact-match
    • label-scoped Cypher remains correct per contract type
    • flag any regression toward fuzzy or unscoped matching
  • Graph schema integrity is preserved:
    • no silent changes to node labels
    • no silent changes to edge types
    • no silent changes to ID generation (generateId)
  • Call out any missing wiring, partial integration, dead branch, or mismatch between tests and runtime behavior

2. Code clarity & clean code

Check:

  • naming quality
  • local cohesion
  • dead code
  • unnecessary abstraction
  • hidden control flow
  • confusing indirection
  • adherence to repo conventions:
    • direct imports from gitnexus-shared
    • no barrel re-export regressions
    • no // removed comments
    • no unused re-exports
  • no drive-by refactors outside stated scope per CONTRIBUTING.md and GUARDRAILS.md § Scope

3. Test coverage & change safety

Evaluate against TESTING.md:

  • Are there unit tests under gitnexus/test/unit/ covering the newly wired path?
  • Is there a regression guard for 0-link → N-link behavior?
  • Are assertions meaningful rather than tautological?
  • Are fixtures realistic for manifest inputs?
  • If memoization/cache was introduced, is there a test proving hit/miss behavior and correctness?
  • Is there evidence the expected validation path would pass for staged gitnexus/ files?
    • tsc --noEmit
    • vitest run --project default
      If not verifiable, say exactly what is missing.

4. Performance

Inspect for:

  • hot-path overhead in ingestion/group sync
  • excess allocations per manifest entry
  • redundant Cypher round-trips
  • missed batching or missed parallelism (Promise.all) where it materially matters
  • O(n²) or repeated lookup patterns on large repos
  • memoization tradeoffs:
    • correctness
    • invalidation
    • bounded vs unbounded memory growth
      Do not speculate casually; explain the mechanism and likely impact.

5. Operational risk

Check:

  • Windows/cross-platform safety:
    • stream lifecycle
    • FD/file handle lifecycle
    • path separator assumptions
    • anything resembling prior ENOTEMPTY-style lifecycle regressions
  • LadybugDB single-writer invariant is preserved
  • Embeddings preservation:
    • no silent breakage of --embeddings
    • .gitnexus/meta.json.stats.embeddings not silently zeroed by changed paths
  • MCP contracts remain compatible:
    • group_*
    • query
    • context
    • impact
    • detect_changes
    • rename
    • cypher
      Flag any schema or contract break without migration note
  • staleness behavior still triggers correctly (gitnexus/src/mcp/staleness.ts)
  • rollback safety:
    • can this PR be reverted safely without re-analyze?
    • if not, explain why

6. Maintainability

Check:

  • Does the change respect Pipeline Phase DAG boundaries?
  • Is cross-phase coupling being introduced?
  • Are manifest-extractor entry points discoverable from group/sync.ts?
  • Would the next contributor know where to extend this?
  • Is shared logic placed appropriately:
    • in gitnexus-shared/
    • or gitnexus/src/core/**/utils.ts
    • and not duplicated between CLI and web bridge (server/api.ts)?

NON-NEGOTIABLES TO VERIFY
From GUARDRAILS.md / CONTRIBUTING.md:

  • no secrets, tokens, or machine-specific paths committed
  • no blind find-and-replace renames
  • if a symbol rename occurred, rename MCP tool or equivalent careful review was used
  • upstream impact was considered for modified shared symbols
  • no HIGH/CRITICAL impact left unaddressed
  • PR title follows conventional commit style + [area] Short description
  • PolyForm Noncommercial license headers/metadata untouched

OUTPUT FORMAT

Production-ready bar for this PR

Give a concise repo-specific definition in 5–10 bullets.

Findings

For each finding, use this structure exactly:

[BLOCKING|NON-BLOCKING|NIT] Short title

  • Evidence: path:line, path:line
  • Why it matters: ...
  • Recommendation: ...
  • Confidence: High / Medium / Low

Only include findings that are real and supported.
If there are no findings in a section, say:

  • No issues found in this area based on the diff and reviewed context.

What I could not fully verify

List any behavior you could not prove from the diff, tests, or available context.

Final verdict

Choose exactly one:

  • ✅ Ready to merge — no blocking issues.
  • ⚠️ Merge after addressing blocking items.
  • ❌ Not ready — fundamental concerns.

If verdict is not ready, list the blocking items in priority order.


IMPORTANT REVIEW BEHAVIOR

  • Be strict on correctness and contracts.
  • Be conservative about operational risk.
  • Be explicit about uncertainty.
  • Do not suggest unrelated refactors.
  • Do not turn nits into blockers.
  • Do not reward intent; review actual implementation.

You must also ensure we are on track with the RFC plan! Check the issue tickets involved!

@github-actions

github-actions Bot commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

Claude finished @magyargergo's task in 3m 27s —— View job


PR Review: feat(shared): MethodDispatchIndex #960

Tasks


Production-ready bar for this PR

Based on AGENTS.md, GUARDRAILS.md, CONTRIBUTING.md, TESTING.md, ARCHITECTURE.md, and the affected area (gitnexus-shared/src/scope-resolution/):


Findings

1. Correctness & functional completeness

  • No issues found based on the diff and reviewed context.

Verified:

  • mroByOwnerDefId is correctly populated: loop over input.owners, first-write-wins guard at method-dispatch-index.ts:88, computeMro not called for duplicate owners. ✅
  • implsByInterfaceDefId inversion is correct: implsSeen Map prevents duplicate (ifaceId, ownerId) pairs regardless of how many times an owner appears in input.owners. ✅
  • EMPTY frozen sentinel shared on miss for both lookup methods (method-dispatch-index.ts:121). ✅
  • chain.slice() + Object.freeze at line 90 guarantees callback-array isolation + frozen storage. ✅
  • Export block in index.ts:78-83 correctly exports buildMethodDispatchIndex, MethodDispatchIndex, MethodDispatchInput. DefId is already re-exported from types.js at line 35 so the test import type DefId from 'gitnexus-shared' resolves correctly. ✅

2. Code clarity & clean code

  • No issues found in this area based on the diff and reviewed context.

Verified against repo conventions:

  • Direct imports from gitnexus-shared in test (method-dispatch-index.test.ts:12). ✅
  • No // removed comments, no unused re-exports, no drive-by refactors. ✅
  • Pattern matches sibling def-index.ts exactly: mutable build → freezeIndex → typed interface. ✅

NIT: C3 and BFS linearization tests are identical

  • Evidence: method-dispatch-index.test.ts:61-76
  • Why it matters: Both tests use { 'def:D': ['def:B', 'def:C', 'def:A'] } with identical setup and assertion. Since the index is a pure pass-through materializer, these tests are structurally indistinguishable. The intent (demonstrating C3 vs BFS produce different orderings) is valid, but both tests share the same MRO array and don't exercise that distinction.
  • Recommendation: Either use different MRO orderings in each test (e.g., ['def:B', 'def:A', 'def:C'] vs ['def:B', 'def:C', 'def:A'] to illustrate that different strategies produce different results that are both faithfully stored), or merge into a single parameterized test. Not merge-blocking since the materializer correctness is covered by other tests.
  • Confidence: High

3. Test coverage & change safety

  • No blocking gaps. 19 tests cover all stated safety properties.

Verified:

  • All 19 tests under correct path gitnexus/test/unit/scope-resolution/. ✅
  • Assertions are non-tautological (concrete toEqual arrays, mutation-throw checks). ✅
  • Frozen-miss behavior (mroFor('def:Missing'), implementorsOf('def:Missing')) explicitly tested and throws on push. ✅
  • Callback-array isolation test (method-dispatch-index.test.ts:183-192) is particularly rigorous. ✅

NON-BLOCKING: implementsOf call count not verified in first-write-wins test

  • Evidence: method-dispatch-index.test.ts:134-151 only asserts mroCalls === 1; no counter for implementsOf.
  • Why it matters: Unlike computeMro, implementsOf is called for every occurrence of an owner in input.owners, including duplicates (see method-dispatch-index.ts:93 — no has guard around the implementsOf call). The dedup logic in implsSeen ensures correct output, but the callback fires twice for duplicate owners. A future refactor that accidentally skips implementsOf for duplicate owners would pass this test if the dedup coincidentally produced the right output (it would in this case).
  • Recommendation: Add an implementsOfCalls counter assertion alongside mroCalls in the duplicate-owner test. Alternatively, add a doc comment to buildMethodDispatchIndex clarifying that implementsOf is called once per occurrence of an owner in input.owners (not once per unique owner), so callers with expensive callbacks know the contract.
  • Confidence: High

4. Performance

  • No issues found in this area based on the diff and reviewed context.

buildMethodDispatchIndex is a one-time startup cost (called when #917 builds the Registry), not a hot query path. O(owners × avg_interfaces_per_owner) construction. The implsSeen auxiliary Map<DefId, Set<DefId>> is GC'd after construction. EMPTY singleton prevents per-miss allocations on lookup. No Cypher round-trips, no filesystem I/O.

5. Operational risk

  • No issues found in this area based on the diff and reviewed context.

Pure in-memory data structure: no filesystem, no streams, no FD lifecycle, no path separators. LadybugDB, embeddings, MCP contracts, and staleness logic are all untouched. Rollback is safe — #917 has not landed yet, so there are no downstream consumers of the new exports in any currently merged code.

6. Maintainability

  • No issues found in this area based on the diff and reviewed context.

Module placed in gitnexus-shared/src/scope-resolution/ alongside def-index.ts, module-scope-index.ts, qualified-name-index.ts, resolve-type-ref.ts — the right call for consistency over the suggested flat placement. RFC comment in index.ts:78 (RFC §3.1; Ring 2 SHARED #914) makes it discoverable. No Pipeline Phase DAG boundaries crossed; no cross-phase coupling introduced.


Non-negotiables

Check Status
No secrets / tokens / machine paths
No blind find-and-replace renames ✅ (new file only)
Upstream impact considered ✅ (new symbols, no existing code modified)
No HIGH/CRITICAL unaddressed
PR title conventional commit format feat(shared):
PolyForm license untouched
No language-specific code in shared ingestion ✅ (callbacks keep strategies CLI-local)

RFC #909 Ring 2 tracker

Issue Description Status
#910 scope-resolution types + constants ✅ merged (#949)
#911 LanguageProvider scope-resolution hooks ✅ merged (#950)
#913 DefIndex / ModuleScopeIndex / QualifiedNameIndex ✅ merged (#958)
#914 MethodDispatchIndex this PR
#916 resolveTypeRef strict resolver ✅ merged (#959)
#918 shadow-mode diff + aggregate ✅ merged (#951)
#917 Registry.lookupMethod MRO fast path 🔜 unblocked by this PR

This PR is the last outstanding Ring 2 SHARED deliverable before #917 can proceed. The RFC is on track.


What I could not fully verify

  • tsc --noEmit clean: PR description asserts it passes for both gitnexus-shared and gitnexus. Cannot run locally without installing deps, but the TypeScript is structurally sound — no type errors are visible in the diff.
  • Combined 170/170 test pass: PR description asserts this. Cannot verify CI results from the diff alone.
  • implementsOf is never called with a duplicate owner when computeMro first-write-wins guards apply — this asymmetry exists by design (dedup handles the output), but the call-count behavior is unverified in tests (see NON-BLOCKING finding above).

Final verdict

Ready to merge — no blocking issues.

The implementation is correct, the safety surface matches sibling indexes precisely, the test suite is thorough, and the RFC Ring 2 tracker is in good shape. The two findings (NON-BLOCKING + NIT) are worth addressing in a follow-up or pre-merge if time permits, but neither affects correctness or safety.

@github-actions

Copy link
Copy Markdown
Contributor

CI Report

All checks passed

Pipeline Status

Stage Status Details
✅ Typecheck success tsc --noEmit
✅ Tests success unit tests, 3 platforms
✅ E2E success gitnexus-web changes only

Test Results

Tests Passed Failed Skipped Duration
6699 6602 0 97 262s

✅ All 6602 tests passed

97 test(s) skipped — expand for details
  • Swift MethodExtractor > isTypeDeclaration > recognizes class_declaration
  • Swift MethodExtractor > isTypeDeclaration > recognizes protocol_declaration
  • Swift MethodExtractor > isTypeDeclaration > rejects import_declaration
  • Swift MethodExtractor > visibility > extracts public method
  • Swift MethodExtractor > visibility > extracts private method
  • Swift MethodExtractor > visibility > defaults to internal when no modifier
  • Swift MethodExtractor > protocol methods > marks protocol method as abstract
  • Swift MethodExtractor > static and class methods > detects static func as isStatic
  • Swift MethodExtractor > static and class methods > detects class func as isStatic
  • Swift MethodExtractor > parameters > extracts parameters with types and default values
  • Swift MethodExtractor > return type > extracts return type from -> annotation
  • Swift MethodExtractor > annotations > extracts @objc attribute
  • Swift MethodExtractor > isFinal > detects final func
  • Swift MethodExtractor > isFinal > is false when not final
  • Swift MethodExtractor > isAsync > detects async func
  • Swift MethodExtractor > isOverride > detects override method
  • buildTypeEnv > constructor inference (Tier 1 fallback) > lookupClassByName regression coverage > Swift lookupClassByName regression coverage > Swift cross-file constructor inference uses lookupClassByName
  • buildTypeEnv > constructor inference (Tier 1 fallback) > lookupClassByName regression coverage > Swift lookupClassByName regression coverage > Swift explicit init inference uses lookupClassByName
  • buildTypeEnv > constructor inference (Tier 1 fallback) > lookupClassByName regression coverage > Swift lookupClassByName regression coverage > Swift cross-file constructor inference does not bind plain functions
  • buildTypeEnv > known limitations (documented skip tests) > Ruby block parameter: users.each { |user| } — closure param inference, different feature
  • Swift constructor-inferred type resolution > detects User and Repo classes, both with save methods
  • Swift constructor-inferred type resolution > resolves user.save() to Models/User.swift via constructor-inferred type
  • Swift constructor-inferred type resolution > resolves repo.save() to Models/Repo.swift via constructor-inferred type
  • Swift constructor-inferred type resolution > emits exactly 2 save() CALLS edges (one per receiver type)
  • Swift self resolution > detects User and Repo classes, each with a save function
  • Swift self resolution > resolves self.save() inside User.process to User.save, not Repo.save
  • Swift parent resolution > detects BaseModel and User classes plus Serializable protocol
  • Swift parent resolution > emits EXTENDS edge: User → BaseModel
  • Swift parent resolution > emits IMPLEMENTS edge: User → Serializable (protocol conformance)
  • Swift cross-file User.init() inference > resolves user.save() via User.init(name:) inference
  • Swift cross-file User.init() inference > resolves user.greet() via User.init(name:) inference
  • Swift return type inference > detects User class and getUser function
  • Swift return type inference > detects save function on User (Swift class methods are Function nodes)
  • Swift return type inference > resolves user.save() to User#save via return type of getUser() -> User
  • Swift return-type inference via function return type > resolves user.save() to User#save via return type of getUser()
  • Swift return-type inference via function return type > user.save() does NOT resolve to Repo#save
  • Swift return-type inference via function return type > resolves repo.save() to Repo#save via return type of getRepo()
  • Swift implicit imports (cross-file visibility) > detects UserService class in Models.swift
  • Swift implicit imports (cross-file visibility) > resolves UserService() constructor call across files (no explicit import)
  • Swift implicit imports (cross-file visibility) > resolves service.fetchUser() member call across files
  • Swift implicit imports (cross-file visibility) > creates IMPORTS edges between files in the same module
  • Swift extension deduplication > detects Product class
  • Swift extension deduplication > resolves Product() constructor despite extension creating duplicate class node
  • Swift extension deduplication > resolves product.save() to Product.swift (primary definition)
  • Swift constructor call fallback (no new keyword) > resolves OCRService() as constructor call across files
  • Swift constructor call fallback (no new keyword) > resolves ocr.recognize() member call via constructor-inferred type
  • Swift export visibility (internal vs private) > resolves PublicService() constructor across files
  • Swift export visibility (internal vs private) > resolves internalHelper() across files (internal = module-scoped)
  • Swift if let / guard let binding resolution > detects User and Repo classes
  • Swift if let / guard let binding resolution > resolves user.save() inside if-let to User#save
  • Swift if let / guard let binding resolution > resolves repo.save() inside guard-let to Repo#save
  • Swift if let / guard let binding resolution > user.save() in if-let does NOT resolve to Repo#save
  • Swift await / try expression unwrapping > resolves user.save() via await fetchUser() return type
  • Swift await / try expression unwrapping > resolves repo.save() via try parseRepo() return type
  • Swift await / try expression unwrapping > detects fetchUser and parseRepo as functions
  • Swift for-in loop element type inference > detects User and Repo classes
  • Swift for-in loop element type inference > creates implicit import edges between files
  • Swift field-type resolution > detects classes and their properties
  • Swift field-type resolution > emits HAS_PROPERTY edges from class to field
  • Swift field-type resolution > resolves field-chain call user.address.save() → Address#save
  • Swift field-type resolution > emits ACCESSES edges for field reads in chains
  • Swift field-type resolution > populates field metadata (visibility, declaredType) on Property nodes
  • Swift call-result binding > resolves call-result-bound method call user.save() → User#save
  • Swift call-result binding > getUser() is present as a defined function
  • Swift call-result binding > emits processUser -> getUser CALLS edge for let-assigned free function call
  • Swift method enrichment > detects Animal protocol and Dog class
  • Swift method enrichment > emits IMPLEMENTS edge Dog -> Animal
  • Swift method enrichment > emits HAS_METHOD edges for Dog methods
  • Swift method enrichment > marks protocol Animal.speak as isAbstract
  • Swift method enrichment > marks Dog.speak as NOT isAbstract
  • Swift method enrichment > marks breathe as isFinal
  • Swift method enrichment > marks classify as isStatic
  • Swift method enrichment > captures @objc annotation on breathe
  • Swift method enrichment > populates parameterTypes for classify(_ name: String)
  • Swift method enrichment > records parameterCount for classify
  • Swift method enrichment > records returnType for speak
  • Swift method enrichment > resolves dog.speak() CALLS edge
  • Swift method enrichment > resolves Dog.classify("dog") CALLS edge
  • Swift abstract dispatch > detects Repository protocol and SqlRepository class
  • Swift abstract dispatch > emits IMPLEMENTS edge SqlRepository -> Repository
  • Swift abstract dispatch > emits HAS_METHOD edges for Repository.find and Repository.save
  • Swift abstract dispatch > emits HAS_METHOD edges for SqlRepository.find and SqlRepository.save
  • Swift abstract dispatch > marks base Repository.find as isAbstract
  • Swift abstract dispatch > marks base Repository.save as isAbstract
  • Swift abstract dispatch > marks concrete SqlRepository.find as NOT isAbstract
  • Swift abstract dispatch > resolves repo.find(id: 42) CALLS edge
  • Swift abstract dispatch > resolves repo.save(entity: user) CALLS edge
  • Swift abstract dispatch > populates parameterTypes for Repository.find
  • Swift abstract dispatch > populates parameterTypes for Repository.save
  • Swift abstract dispatch > records returnType for SqlRepository.find
  • Swift abstract dispatch > emits METHOD_IMPLEMENTS edges from SqlRepository methods → Repository protocol methods
  • Swift overloaded method disambiguation > detects 2 distinct find Method nodes on SqlRepository
  • Swift overloaded method disambiguation > emits METHOD_IMPLEMENTS edges for both find overloads
  • Swift overloaded method disambiguation > emits METHOD_IMPLEMENTS edge for save
  • Swift overloaded method disambiguation > emits exactly 3 METHOD_IMPLEMENTS edges total
  • Swift Child extends Parent — inherited method resolution (SM-9) > detects Parent and Child classes
  • Swift Child extends Parent — inherited method resolution (SM-9) > resolves c.parentMethod() to Parent.parentMethod via first-wins MRO walk

Code Coverage

Tests

Metric Coverage Covered Base Delta Status
Statements 73.25% 17890/24423 73.25% = 0.0 🟢 ██████████████░░░░░░
Branches 62.3% 11384/18271 62.3% = 0.0 🟢 ████████████░░░░░░░░
Functions 77.84% 1694/2176 77.84% = 0.0 🟢 ███████████████░░░░░
Lines 75.8% 16215/21390 75.8% = 0.0 🟢 ███████████████░░░░░

📋 View full run · Generated by CI

@magyargergo magyargergo merged commit 5d76dbc into main Apr 18, 2026
19 checks passed
@magyargergo magyargergo deleted the rfc/scope-resolution/914-method-dispatch-index branch April 18, 2026 15:28
github714801013 pushed a commit to github714801013/GitNexus that referenced this pull request Apr 28, 2026
…bhigyanpatwari#914, RFC abhigyanpatwari#909 Ring 2 SHARED) (abhigyanpatwari#960)

Implements RFC §3.1 `MethodDispatchIndex`: a two-way materialized view
keyed by `DefId` for O(1) method-dispatch resolution:

  - `mroByOwnerDefId`       — owner class → full MRO ancestor chain
                              (excludes self, per-language strategy order)
  - `implsByInterfaceDefId` — interface/trait → classes that implement it

**Not an MRO implementation.** `buildMethodDispatchIndex` is a pure
aggregator that calls back into caller-provided `computeMro` and
`implementsOf` functions. The five existing strategies (Python C3, Ruby
kind-aware, Java/Kotlin linear, Rust qualified-syntax, COBOL none) stay
where they are today (`model/resolve.ts`, `languages/ruby.ts`); this index
does not reimplement them.

Why callbacks rather than a shared registry: the strategies depend on the
CLI's `HeritageMap` + `SemanticModel`. Migrating both to `gitnexus-shared`
is out of scope for abhigyanpatwari#914; callbacks let the shared build stay pure.

Module placement: `gitnexus-shared/src/scope-resolution/method-dispatch-index.ts`
for consistency with the other RFC §3.1 indexes (abhigyanpatwari#913 DefIndex /
ModuleScopeIndex / QualifiedNameIndex; abhigyanpatwari#916 resolveTypeRef).

Safety surface mirrors sibling indexes:
  - First-write-wins on duplicate owners.
  - Repeated (interface, owner) pairs deduplicated.
  - Stored arrays are `Object.freeze`d; caller mutation of the source
    array does not leak into the index.
  - Miss returns a shared frozen empty array.

Tests (19, all passing): empty input, single-inheritance chain, Python
C3 diamond, Java BFS, Ruby kind-aware mixin, Rust qualified-syntax empty,
interface inversion (single, multiple, ordered), dedup within and across
callback calls, frozen miss + bucket arrays, callback-array isolation,
readonly Map iteration.

Closes part of abhigyanpatwari#909.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RING2-SHARED-3: MethodDispatchIndex build function over HeritageMap

1 participant